#include <iostream>
#include <new>

/*

在C++中，类的成员可以使用作用域解析运算符::来访问。这包括类的静态成员、嵌套类型和枚举类型。使用::可以在类的作用域内访问成员，而不需要创建类的实例。
类的成员也可以使用对象或指针来访问，但使用::可以直接在类的作用域内访问成员，而不需要创建对象或指针。
*/

template<typename Vector>
class VectorIterator
{
public:
     using ValueType = typename Vector::ValueType;
     using PointerType = ValueType*; 
     using ReferenceType = ValueType&;
public:
     VectorIterator(PointerType ptr) : m_Ptr(ptr) {}

     VectorIterator& operator++()
     {
        m_Ptr++;
        return *this;
     }

     VectorIterator operator++(int)
     {
        VectorIterator iterator = *this;
        ++(*this); 
        return iterator;
     }

     VectorIterator& operator--()
     {
        m_Ptr--;
        return *this;
     }

     VectorIterator operator--(int)
     {
        VectorIterator iterator = *this;
        -- (*this); 
        return iterator;
     }

     ReferenceType operator[](int index)
     {
          return *(m_Ptr + index);
     }

     PointerType operator->()
     {
        return m_Ptr;
     }

     ReferenceType operator*()
     {
        return *m_Ptr;
     }

     bool operator==(const VectorIterator& other) const 
     {
        return m_Ptr == other.m_Ptr; 
     }

    bool operator!=(const VectorIterator& other) const 
     {
        return !(*this == other); 
     }

private:
    PointerType m_Ptr;     
};

template<typename T>
class Vector
{
public:

/*
ValueType是Vector类的一个类型成员。它使用using关键字声明了一个类型别名，将模板参数T赋值给ValueType。
这样做的目的是为了在Vector类内部和外部使用ValueType来表示Vector中存储的元素类型。通过这种方式，
可以在代码中使用ValueType来指代Vector中的元素类型，而不需要显式地指定模板参数T

 如： using ValueType = int; // 类型别名
*/
     using ValueType = T; 
     using Iterator = VectorIterator<Vector<T> >;
public: 
     Vector()
     {
        ReAlloc(2);
     }

     ~Vector()
     {
        Clear(); //进行调用所有容器内对象的析构函数
        //delete[] m_Data;
        ::operator delete(m_Data, m_Capacity * sizeof(T));//这不会调用任何析构函数
     }

    void PushBack(const T& value)
    {
        if(m_Size >= m_Capacity)
        {
            ReAlloc(m_Capacity + m_Capacity / 2);
        }
        m_Data[m_Size] = value;
        m_Size++;
    }

    void PushBack(T&& value)
    {
        if(m_Size >= m_Capacity)
        {
            ReAlloc(m_Capacity + m_Capacity / 2);
        }
        m_Data[m_Size] = std::move(value);
        m_Size++;
    }

/*
std::forward是一个非常有用的函数模板，用于实现完美转发，确保参数以原始的形式传递给其他函数，同时保持参数的值类别

template <typename... Args>是一个模板声明，用于定义一个接受可变数量模板参数的函数模板或类模板。
Args是一个模板参数包的名称，用于表示这些模板参数，并在模板定义中使用展开操作来访问和使用这些参数
Args是一个模板参数包，用于接收可变数量的模板参数，并在函数模板中实现对这些参数的处理和转发
*/

    template<typename... Args>
    T& EmplaceBack(Args&&... args) //注意返回的是引用
    {
        if(m_Size >= m_Capacity)
              ReAlloc(m_Capacity + m_Capacity / 2);
        
        // 已存在的内存中 适当的位置进行构建事物 placement new
        // 使用placement new在已分配的内存位置上构造一个新的对象。它在已分配的内存位置上调用类型T的构造函数
        new(&m_Data[m_Size]) T(std::forward<Args>(args)...);
        //下面代码会构造对象 进行移动赋值
        //m_Data[m_Size] = T(std::forward<Args>(args)...); //构造T对象， std::forward<Args>(args)...进行解压缩 这些参数
        return m_Data[m_Size++];
    }

    /*
    new (&m_Data[m_Size]) T(std::forward<Args>(args)...);使用placement new在已分配的内存中构造对象，
    而m_Data[m_Size] = T(std::forward<Args>(args)...);使用赋值操作符(移动赋值)将新构造的对象赋给已存在的对象。
    */

    void PopBack()
    {
        if(m_Size > 0)
        {
            m_Size--;
            m_Data[m_Size].~T();
        }
    }

    void Clear()
    {
        for(size_t i = 0; i < m_Size; i++)
        {
            m_Data[i].~T();
        }

        m_Size = 0;
    }

    T& operator[](size_t index)
    {
        if(index >= m_Size)
        {
            //assert
        }
        return m_Data[index];
    }

    const T& operator[](size_t index) const 
    {
        if(index >= m_Size)
        {
            //assert
        }
        return m_Data[index];
    }
 
    size_t Size() const {return m_Size; }

    Iterator end()
    {
        return Iterator(m_Data + m_Size);
    }

    Iterator begin()
    {
        return Iterator(m_Data);
    }
private:
      void ReAlloc(size_t newCapacity)
      {
        // 1. allocate a new block of memory
        // 2. copy/move old elements to new block
        // 3. delete
        
        //T* newBlock = new T[newCapacity];
        //改变内存分配方式，防止重复析构
        T* newBlock = (T*)::operator new(newCapacity * sizeof(T));

         //增大或缩小我们的vector
        if(newCapacity < m_Size) //重新分配的大小 < 原来的大小，注意内存分配的大小是否溢出
        {
            m_Size = newCapacity;
        }
        for(size_t i = 0;i < m_Size; i++)
        {
            //如果没有这种类型的移动构造函数，就 复制
            //重新分配内存时，也进行移动
            /*
            使用std::string 会崩溃
            你不能在这里使用赋值操作符(无论是移动还是复制)，因为newBlock[i]是未初始化的内存-它不是类型T的对象，
            通过调用operator=(再次移动或不移动)，你把它当作类型T的对象。因此，你应该再次使用placement new，
            因此将该行更改为:new (&newData[i]) T(std::move(m_Data[i]))
            */
            //newBlock[i] = std::move(m_Data[i]); //不实用memcpy的原因是：对于自定义数据，需要调用相应的拷贝赋值函数
            new (&newBlock[i]) T(std::move(m_Data[i]));
            //newBlock[i] = m_Data[i];
        }

        //删除old数据
        //改变内存释放方式，防止重复析构
        //delete[] m_Data;
        //调用容器内对象析构函数
         for(size_t i = 0; i < m_Size; i++)
              m_Data[i].~T(); //不能调用Clear()函数，会把m_Size = 0
        
        //再释放容器old分配的空间
        ::operator delete(m_Data, m_Capacity * sizeof(T));
        m_Data = newBlock;
        m_Capacity = newCapacity;
      }
private:
    T* m_Data = nullptr;
    size_t m_Size = 0;
    size_t m_Capacity = 0;    
 };


struct Vector3
{
    float x = 0.0f, y = 0.0f, z = 0.0f;
    int* m_MemoryBlock = nullptr;

    Vector3() {  m_MemoryBlock = new int[5]; }
    Vector3(float scalar) : x(scalar),y(scalar),z(scalar) {
        m_MemoryBlock = new int[5];
    }
    Vector3(float x, float y, float z) : x(x), y(y), z(z) {
         m_MemoryBlock = new int[5];
    }

    Vector3(const Vector3& other) = delete;
    // Vector3(const Vector3& other) //复制构造函数
    // : x(other.x), y(other.y), z(other.z)
    // {
    //     std::cout << "Copy!" << std::endl;
    // } 
 
   Vector3(Vector3&& other) //针对移动构造，移动赋值，不要加const 
    : x(other.x), y(other.y), z(other.z)
    {
        m_MemoryBlock = other.m_MemoryBlock;
        other.m_MemoryBlock = nullptr;
        
        std::cout << "Move!" << std::endl;
    } 
    ~Vector3()
    {
        std::cout << "Destory!" << std::endl;
        delete[] m_MemoryBlock;
    }

    Vector3& operator=(const Vector3& other) = delete;
    // Vector3& operator=(const Vector3& other) // 拷贝赋值
    // {
    //     std::cout << "Copy = !" << std::endl;
    //     x = other.x;
    //     y = other.y;
    //     z = other.z;

    //     return *this;
    // } 
 
    Vector3& operator=(Vector3&& other) //移动赋值
    {
        m_MemoryBlock = other.m_MemoryBlock;
        other.m_MemoryBlock = nullptr;

        std::cout << "Move = !" << std::endl;
        x = other.x;
        y = other.y;
        z = other.z;

        return *this;
    } 
        

};

template<typename T>
void PrintVector(const Vector<T>& vector)
{
    for(size_t i = 0; i < vector.Size(); i++)
    {
        std::cout << vector[i] << std::endl;
    }

    std::cout << "------------------" << std::endl;
}

template<>
void PrintVector(const Vector<Vector3>& vector)
{
    for(size_t i = 0; i < vector.Size(); i++)
    {
        std::cout << vector[i].x << vector[i].y << vector[i].z  << std::endl;
    }

    std::cout << "------------------" << std::endl;
}

int main()
{
    Vector<std::string> vec;
    vec.EmplaceBack("caoxiansheng");
    vec.EmplaceBack("c++");
    vec.EmplaceBack("Today");
    vec.EmplaceBack("is");
    vec.EmplaceBack("Tursday");

    std::cout << "vec size(): " << vec.Size() << std::endl;
    //PrintVector(vec);

    for(int i = 0; i < vec.Size(); i++)
    {
        std::cout << vec[i] << std::endl;
    }

    for(auto& value : vec)
    {
        std::cout << value << std::endl;
    }

    for(Vector<std::string>::Iterator it = vec.begin(); it != vec.end(); it++)
    {
        std::cout << *it << std::endl;
    }
//  {
//     Vector<Vector3> data;
//     // data.PushBack(Vector3(1.0f)); //实际不会原地构造对象，只是将到移动到data内部拥有的数据储存中，在我的数据块中就地构建 
//     // data.PushBack(Vector3(2, 3, 4));
//     // data.PushBack(Vector3());

//     data.EmplaceBack(1.0f); //接受一个参数列表
//     data.EmplaceBack(2, 3, 4);
//     PrintVector(data);
//     data.EmplaceBack(); //若此时进行vector增量，则扩容2+1，再进行3次移动拷贝
//     PrintVector(data);
//     data.PopBack();
//     data.PopBack();
//        PrintVector(data);
//     data.EmplaceBack(1, 7, 9);
//     data.EmplaceBack(5, 2, 0);
//     data.EmplaceBack(9, 1, 1);
//     PrintVector(data);
//     data.Clear();
//     PrintVector(data);
//  }

}